423d3a7b2vJq86I8FbYm6up5BsCwfA tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in
423d3a7bQPownmVb63qOoyq89ebBVA tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv
423d3a7bHtqhyOgiRWhjWt-S-6wbYg tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
+4273458dYPghQKVnj_xu5-fC38CcOg tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c
423d3a7b2ENk2IskDZYZ98pe5NsvIA tools/gdb/gdb-6.2.1-xen-sparse/mkbuildtree
423d3a7buANO_q-kgxIRffUu7lMnUw tools/gdb/gdbbuild
41e2ff6dNPgvIrdIF6dC1azdex1U3A tools/ioemu/Makefile
3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec
3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h
3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/libxc/xc_bvtsched.c
+4273458dyF2_sKA6CFkNJQYb8eY2dA tools/libxc/xc_core.c
3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxc/xc_domain.c
40278d99BLsfUv3qxv0I8C1sClZ0ow tools/libxc/xc_elf.h
403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/libxc/xc_evtchn.c
3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c
3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h
42337174PxyzzPk62raDiYCIsfStDg tools/libxc/xc_ptrace.c
+4273458duzL--nsTfT6e_q6Kfij48g tools/libxc/xc_ptrace_core.c
41dde8b0pLfAKMs_L9Uri2hnzHiCRQ tools/libxc/xc_vmx_build.c
40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile
40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c
# -I. for config files.
# -I${srcdir} for our headers.
# -I$(srcdir)/../regformats for regdef.h.
-INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR)
+INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) -I../../../../libxc/ -I../../../../libxutil/
# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS
# from the config/ directory.
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
-
+#include <xc.h>
#define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */
-#define ptrace xc_ptrace
-long xc_ptrace(enum __ptrace_request request, ...);
+long (*myptrace)(enum __ptrace_request, pid_t, long, long);
+int (*myxcwait)(int domain, int *status, int options) ;
-int waitdomain(int domain, int *status, int options);
#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
#define DOMFLAGS_CRASHED (1<<1) /* Crashed domain; frozen for postmortem. */
int debug_threads;
int using_threads;
+extern int isfile;
+
struct pending_signals
{
int signal;
{
struct process_info *new_process;
current_domain = domain;
- if (ptrace (PTRACE_ATTACH, domain, 0, 0) != 0) {
+ if (myptrace (PTRACE_ATTACH, domain, 0, 0) != 0) {
fprintf (stderr, "Cannot attach to domain %d: %s (%d)\n", domain,
strerror (errno), errno);
fflush (stderr);
{
struct thread_info *thread = (struct thread_info *) entry;
struct process_info *process = get_thread_process (thread);
- ptrace (PTRACE_KILL, pid_of (process), 0, 0);
+ myptrace (PTRACE_KILL, pid_of (process), 0, 0);
}
struct thread_info *thread = (struct thread_info *) entry;
struct process_info *process = get_thread_process (thread);
- ptrace (PTRACE_DETACH, pid_of (process), 0, 0);
+ myptrace (PTRACE_DETACH, pid_of (process), 0, 0);
}
linux_wait (char *status)
{
int w;
- TRACE_ENTER;
- if (waitdomain(current_domain, &w, 0))
+ if (myxcwait(current_domain, &w, 0))
return -1;
if (w & (DOMFLAGS_CRASHED|DOMFLAGS_DYING)) {
expect_signal = resume_info->sig;
for_each_inferior(&all_threads, regcache_invalidate_one);
- ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, current_domain, 0, 0);
+ myptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, current_domain, 0, 0);
}
}
buf = malloc (regset->size);
- res = ptrace (regset->get_request, inferior_pid, 0, buf);
+ res = myptrace (regset->get_request, inferior_pid, 0, (PTRACE_XFER_TYPE)buf);
if (res < 0)
{
if (errno == EIO)
buf = malloc (regset->size);
regset->fill_function (buf);
- res = ptrace (regset->set_request, inferior_pid, 0, buf);
+ res = myptrace (regset->set_request, inferior_pid, 0, (PTRACE_XFER_TYPE)buf);
if (res < 0)
{
if (errno == EIO)
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
{
errno = 0;
- buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
+ buffer[i] = myptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
if (errno)
return errno;
}
/* Fill start and end extra bytes of buffer with existing memory data. */
- buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
+ buffer[0] = myptrace (PTRACE_PEEKTEXT, inferior_pid,
(PTRACE_ARG3_TYPE) addr, 0);
if (count > 1)
{
buffer[count - 1]
- = ptrace (PTRACE_PEEKTEXT, inferior_pid,
+ = myptrace (PTRACE_PEEKTEXT, inferior_pid,
(PTRACE_ARG3_TYPE) (addr + (count - 1)
* sizeof (PTRACE_XFER_TYPE)),
0);
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
{
errno = 0;
- ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ myptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
if (errno)
return errno;
}
the_low_target.breakpoint_len);
init_registers ();
linux_init_signals ();
+ if (isfile) {
+ myptrace = xc_ptrace_core;
+ myxcwait = xc_waitdomain_core;
+ } else {
+ myptrace = xc_ptrace;
+ myxcwait = xc_waitdomain;
+ }
+
}
--- /dev/null
+/* Main code for remote server for GDB.
+ Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "server.h"
+
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int cont_thread;
+int general_thread;
+int step_thread;
+int thread_from_wait;
+int old_thread_from_wait;
+int extended_protocol;
+int server_waiting;
+int isfile = 0;
+
+jmp_buf toplevel;
+
+/* The PID of the originally created or attached inferior. Used to
+ send signals to the process when GDB sends us an asynchronous interrupt
+ (user hitting Control-C in the client), and to wait for the child to exit
+ when no longer debugging it. */
+
+int signal_pid;
+
+static unsigned char
+start_inferior (char *argv[], char *statusptr)
+{
+ signal (SIGTTOU, SIG_DFL);
+ signal (SIGTTIN, SIG_DFL);
+
+ signal_pid = create_inferior (argv[0], argv);
+
+ fprintf (stderr, "Process %s created; pid = %d\n", argv[0],
+ signal_pid);
+
+ signal (SIGTTOU, SIG_IGN);
+ signal (SIGTTIN, SIG_IGN);
+ tcsetpgrp (fileno (stderr), signal_pid);
+
+ /* Wait till we are at 1st instruction in program, return signal number. */
+ return mywait (statusptr, 0);
+}
+
+static int
+attach_inferior (int pid, char *statusptr, unsigned char *sigptr)
+{
+ /* myattach should return -1 if attaching is unsupported,
+ 0 if it succeeded, and call error() otherwise. */
+
+ if (myattach (pid) != 0)
+ return -1;
+
+ fprintf (stderr, "Attached; pid = %d\n", pid);
+
+ /* FIXME - It may be that we should get the SIGNAL_PID from the
+ attach function, so that it can be the main thread instead of
+ whichever we were told to attach to. */
+ signal_pid = pid;
+
+ *sigptr = mywait (statusptr, 0);
+
+ return 0;
+}
+
+extern int remote_debug;
+
+/* Handle all of the extended 'q' packets. */
+void
+handle_query (char *own_buf)
+{
+ static struct inferior_list_entry *thread_ptr;
+
+ if (strcmp ("qSymbol::", own_buf) == 0)
+ {
+ if (the_target->look_up_symbols != NULL)
+ (*the_target->look_up_symbols) ();
+
+ strcpy (own_buf, "OK");
+ return;
+ }
+
+ if (strcmp ("qfThreadInfo", own_buf) == 0)
+ {
+ thread_ptr = all_threads.head;
+ sprintf (own_buf, "m%x", thread_ptr->id);
+ thread_ptr = thread_ptr->next;
+ return;
+ }
+
+ if (strcmp ("qsThreadInfo", own_buf) == 0)
+ {
+ if (thread_ptr != NULL)
+ {
+ sprintf (own_buf, "m%x", thread_ptr->id);
+ thread_ptr = thread_ptr->next;
+ return;
+ }
+ else
+ {
+ sprintf (own_buf, "l");
+ return;
+ }
+ }
+
+ if (the_target->read_auxv != NULL
+ && strncmp ("qPart:auxv:read::", own_buf, 17) == 0)
+ {
+ char data[(PBUFSIZ - 1) / 2];
+ CORE_ADDR ofs;
+ unsigned int len;
+ int n;
+ decode_m_packet (&own_buf[17], &ofs, &len); /* "OFS,LEN" */
+ if (len > sizeof data)
+ len = sizeof data;
+ n = (*the_target->read_auxv) (ofs, data, len);
+ if (n == 0)
+ write_ok (own_buf);
+ else if (n < 0)
+ write_enn (own_buf);
+ else
+ convert_int_to_ascii (data, own_buf, n);
+ return;
+ }
+
+ /* Otherwise we didn't know what packet it was. Say we didn't
+ understand it. */
+ own_buf[0] = 0;
+}
+
+/* Parse vCont packets. */
+void
+handle_v_cont (char *own_buf, char *status, unsigned char *signal)
+{
+ char *p, *q;
+ int n = 0, i = 0;
+ struct thread_resume *resume_info, default_action;
+
+ /* Count the number of semicolons in the packet. There should be one
+ for every action. */
+ p = &own_buf[5];
+ while (p)
+ {
+ n++;
+ p++;
+ p = strchr (p, ';');
+ }
+ /* Allocate room for one extra action, for the default remain-stopped
+ behavior; if no default action is in the list, we'll need the extra
+ slot. */
+ resume_info = malloc ((n + 1) * sizeof (resume_info[0]));
+
+ default_action.thread = -1;
+ default_action.leave_stopped = 1;
+ default_action.step = 0;
+ default_action.sig = 0;
+
+ p = &own_buf[5];
+ i = 0;
+ while (*p)
+ {
+ p++;
+
+ resume_info[i].leave_stopped = 0;
+
+ if (p[0] == 's' || p[0] == 'S')
+ resume_info[i].step = 1;
+ else if (p[0] == 'c' || p[0] == 'C')
+ resume_info[i].step = 0;
+ else
+ goto err;
+
+ if (p[0] == 'S' || p[0] == 'C')
+ {
+ int sig;
+ sig = strtol (p + 1, &q, 16);
+ if (p == q)
+ goto err;
+ p = q;
+
+ if (!target_signal_to_host_p (sig))
+ goto err;
+ resume_info[i].sig = target_signal_to_host (sig);
+ }
+ else
+ {
+ resume_info[i].sig = 0;
+ p = p + 1;
+ }
+
+ if (p[0] == 0)
+ {
+ resume_info[i].thread = -1;
+ default_action = resume_info[i];
+
+ /* Note: we don't increment i here, we'll overwrite this entry
+ the next time through. */
+ }
+ else if (p[0] == ':')
+ {
+ resume_info[i].thread = strtol (p + 1, &q, 16);
+ if (p == q)
+ goto err;
+ p = q;
+ if (p[0] != ';' && p[0] != 0)
+ goto err;
+
+ i++;
+ }
+ }
+
+ resume_info[i] = default_action;
+
+ /* Still used in occasional places in the backend. */
+ if (n == 1 && resume_info[0].thread != -1)
+ cont_thread = resume_info[0].thread;
+ else
+ cont_thread = -1;
+ set_desired_inferior (0);
+
+ (*the_target->resume) (resume_info);
+
+ free (resume_info);
+
+ *signal = mywait (status, 1);
+ prepare_resume_reply (own_buf, *status, *signal);
+ return;
+
+err:
+ /* No other way to report an error... */
+ strcpy (own_buf, "");
+ free (resume_info);
+ return;
+}
+
+/* Handle all of the extended 'v' packets. */
+void
+handle_v_requests (char *own_buf, char *status, unsigned char *signal)
+{
+ if (strncmp (own_buf, "vCont;", 6) == 0)
+ {
+ handle_v_cont (own_buf, status, signal);
+ return;
+ }
+
+ if (strncmp (own_buf, "vCont?", 6) == 0)
+ {
+ strcpy (own_buf, "vCont;c;C;s;S");
+ return;
+ }
+
+ /* Otherwise we didn't know what packet it was. Say we didn't
+ understand it. */
+ own_buf[0] = 0;
+ return;
+}
+
+void
+myresume (int step, int sig)
+{
+ struct thread_resume resume_info[2];
+ int n = 0;
+
+ if (step || sig || cont_thread > 0)
+ {
+ resume_info[0].thread
+ = ((struct inferior_list_entry *) current_inferior)->id;
+ resume_info[0].step = step;
+ resume_info[0].sig = sig;
+ resume_info[0].leave_stopped = 0;
+ n++;
+ }
+ resume_info[n].thread = -1;
+ resume_info[n].step = 0;
+ resume_info[n].sig = 0;
+ resume_info[n].leave_stopped = (cont_thread > 0);
+
+ (*the_target->resume) (resume_info);
+}
+
+static int attached;
+
+static void
+gdbserver_usage (void)
+{
+ error ("Usage:\tgdbserver COMM PROG [ARGS ...]\n"
+ "\tgdbserver COMM --attach PID\n"
+ "\tgdbserver COMM --file COREFILE\n"
+ "\n"
+ "COMM may either be a tty device (for serial debugging), or \n"
+ "HOST:PORT to listen for a TCP connection.\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+ char ch, status, *own_buf, mem_buf[2000];
+ int i = 0;
+ unsigned char signal;
+ unsigned int len;
+ CORE_ADDR mem_addr;
+ int bad_attach;
+ int pid;
+ char *arg_end;
+
+ if (setjmp (toplevel))
+ {
+ fprintf (stderr, "Exiting\n");
+ exit (1);
+ }
+
+ bad_attach = 0;
+ pid = 0;
+ attached = 0;
+ if (argc >= 3 && strcmp (argv[2], "--attach") == 0)
+ {
+ if (argc == 4
+ && argv[3] != '\0'
+ && (pid = strtoul (argv[3], &arg_end, 10)) != 0
+ && *arg_end == '\0')
+ {
+ ;
+ }
+ else
+ bad_attach = 1;
+ }
+ else if (argc >= 3 && strcmp (argv[2], "--file") == 0)
+ {
+ if (argc == 4
+ && argv[3] != '\0')
+ {
+ if ((pid = open(argv[3], O_RDONLY)) <= 0)
+ bad_attach = 1;
+ else
+ isfile = 1;
+ }
+ else
+ bad_attach = 1;
+ }
+
+ if (argc < 3 || bad_attach)
+ gdbserver_usage();
+
+ initialize_low ();
+
+ own_buf = malloc (PBUFSIZ);
+
+ if (pid == 0)
+ {
+ /* Wait till we are at first instruction in program. */
+ signal = start_inferior (&argv[2], &status);
+
+ /* We are now stopped at the first instruction of the target process */
+ }
+ else
+ {
+ switch (attach_inferior (pid, &status, &signal))
+ {
+ case -1:
+ error ("Attaching not supported on this target");
+ break;
+ default:
+ attached = 1;
+ break;
+ }
+ }
+
+ while (1)
+ {
+ remote_open (argv[1]);
+
+ restart:
+ setjmp (toplevel);
+ while (getpkt (own_buf) > 0)
+ {
+ unsigned char sig;
+ i = 0;
+ ch = own_buf[i++];
+ switch (ch)
+ {
+ case 'q':
+ handle_query (own_buf);
+ break;
+ case 'd':
+ remote_debug = !remote_debug;
+ break;
+ case 'D':
+ fprintf (stderr, "Detaching from inferior\n");
+ detach_inferior ();
+ write_ok (own_buf);
+ putpkt (own_buf);
+ remote_close ();
+
+ /* If we are attached, then we can exit. Otherwise, we need to
+ hang around doing nothing, until the child is gone. */
+ if (!attached)
+ {
+ int status, ret;
+
+ do {
+ ret = waitpid (signal_pid, &status, 0);
+ if (WIFEXITED (status) || WIFSIGNALED (status))
+ break;
+ } while (ret != -1 || errno != ECHILD);
+ }
+
+ exit (0);
+
+ case '!':
+ if (attached == 0)
+ {
+ extended_protocol = 1;
+ prepare_resume_reply (own_buf, status, signal);
+ }
+ else
+ {
+ /* We can not use the extended protocol if we are
+ attached, because we can not restart the running
+ program. So return unrecognized. */
+ own_buf[0] = '\0';
+ }
+ break;
+ case '?':
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'H':
+ switch (own_buf[1])
+ {
+ case 'g':
+ general_thread = strtol (&own_buf[2], NULL, 16);
+ write_ok (own_buf);
+ set_desired_inferior (1);
+ break;
+ case 'c':
+ cont_thread = strtol (&own_buf[2], NULL, 16);
+ write_ok (own_buf);
+ break;
+ case 's':
+ step_thread = strtol (&own_buf[2], NULL, 16);
+ write_ok (own_buf);
+ break;
+ default:
+ /* Silently ignore it so that gdb can extend the protocol
+ without compatibility headaches. */
+ own_buf[0] = '\0';
+ break;
+ }
+ break;
+ case 'g':
+ set_desired_inferior (1);
+ registers_to_string (own_buf);
+ break;
+ case 'G':
+ set_desired_inferior (1);
+ registers_from_string (&own_buf[1]);
+ write_ok (own_buf);
+ break;
+ case 'm':
+ decode_m_packet (&own_buf[1], &mem_addr, &len);
+ if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
+ convert_int_to_ascii (mem_buf, own_buf, len);
+ else
+ write_enn (own_buf);
+ break;
+ case 'M':
+ decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
+ if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
+ write_ok (own_buf);
+ else
+ write_enn (own_buf);
+ break;
+ case 'C':
+ convert_ascii_to_int (own_buf + 1, &sig, 1);
+ if (target_signal_to_host_p (sig))
+ signal = target_signal_to_host (sig);
+ else
+ signal = 0;
+ set_desired_inferior (0);
+ myresume (0, signal);
+ signal = mywait (&status, 1);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'S':
+ convert_ascii_to_int (own_buf + 1, &sig, 1);
+ if (target_signal_to_host_p (sig))
+ signal = target_signal_to_host (sig);
+ else
+ signal = 0;
+ set_desired_inferior (0);
+ myresume (1, signal);
+ signal = mywait (&status, 1);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'c':
+ set_desired_inferior (0);
+ myresume (0, 0);
+ signal = mywait (&status, 1);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 's':
+ set_desired_inferior (0);
+ myresume (1, 0);
+ signal = mywait (&status, 1);
+ prepare_resume_reply (own_buf, status, signal);
+ break;
+ case 'k':
+ fprintf (stderr, "Killing inferior\n");
+ kill_inferior ();
+ /* When using the extended protocol, we start up a new
+ debugging session. The traditional protocol will
+ exit instead. */
+ if (extended_protocol)
+ {
+ write_ok (own_buf);
+ fprintf (stderr, "GDBserver restarting\n");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &status);
+ goto restart;
+ break;
+ }
+ else
+ {
+ exit (0);
+ break;
+ }
+ case 'T':
+ if (mythread_alive (strtol (&own_buf[1], NULL, 16)))
+ write_ok (own_buf);
+ else
+ write_enn (own_buf);
+ break;
+ case 'R':
+ /* Restarting the inferior is only supported in the
+ extended protocol. */
+ if (extended_protocol)
+ {
+ kill_inferior ();
+ write_ok (own_buf);
+ fprintf (stderr, "GDBserver restarting\n");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &status);
+ goto restart;
+ break;
+ }
+ else
+ {
+ /* It is a request we don't understand. Respond with an
+ empty packet so that gdb knows that we don't support this
+ request. */
+ own_buf[0] = '\0';
+ break;
+ }
+ case 'v':
+ /* Extended (long) request. */
+ handle_v_requests (own_buf, &status, &signal);
+ break;
+ default:
+ /* It is a request we don't understand. Respond with an
+ empty packet so that gdb knows that we don't support this
+ request. */
+ own_buf[0] = '\0';
+ break;
+ }
+
+ putpkt (own_buf);
+
+ if (status == 'W')
+ fprintf (stderr,
+ "\nChild exited with status %d\n", signal);
+ if (status == 'X')
+ fprintf (stderr, "\nChild terminated with signal = 0x%x\n",
+ signal);
+ if (status == 'W' || status == 'X')
+ {
+ if (extended_protocol)
+ {
+ fprintf (stderr, "Killing inferior\n");
+ kill_inferior ();
+ write_ok (own_buf);
+ fprintf (stderr, "GDBserver restarting\n");
+
+ /* Wait till we are at 1st instruction in prog. */
+ signal = start_inferior (&argv[2], &status);
+ goto restart;
+ break;
+ }
+ else
+ {
+ fprintf (stderr, "GDBserver exiting\n");
+ exit (0);
+ }
+ }
+ }
+
+ /* We come here when getpkt fails.
+
+ For the extended remote protocol we exit (and this is the only
+ way we gracefully exit!).
+
+ For the traditional remote protocol close the connection,
+ and re-open it at the top of the loop. */
+ if (extended_protocol)
+ {
+ remote_close ();
+ exit (0);
+ }
+ else
+ {
+ fprintf (stderr, "Remote side has terminated connection. "
+ "GDBserver will reopen the connection.\n");
+ remote_close ();
+ }
+ }
+}
SRCS :=
SRCS += xc_bvtsched.c
+SRCS += xc_core.c
SRCS += xc_domain.c
SRCS += xc_evtchn.c
SRCS += xc_gnttab.c
SRCS += xc_physdev.c
SRCS += xc_private.c
SRCS += xc_ptrace.c
+SRCS += xc_ptrace_core.c
SRCS += xc_vmx_build.c
CFLAGS += -Wall
typedef int32_t s32;
typedef int64_t s64;
+#include <sys/ptrace.h>
#include <xen/xen.h>
#include <xen/dom0_ops.h>
#include <xen/event_channel.h>
*/
int xc_interface_close(int xc_handle);
+/*
+ * DOMAIN DEBUGGING FUNCTIONS
+ */
+
+typedef struct xc_core_header {
+ unsigned int xch_magic;
+ unsigned int xch_nr_vcpus;
+ unsigned int xch_nr_pages;
+ unsigned int xch_ctxt_offset;
+ unsigned int xch_index_offset;
+ unsigned int xch_pages_offset;
+} xc_core_header_t;
+
+
+long xc_ptrace(enum __ptrace_request request,
+ pid_t pid,
+ long addr,
+ long data);
+
+long xc_ptrace_core(enum __ptrace_request request,
+ pid_t pid,
+ long addr,
+ long data);
+
+int xc_waitdomain(int domain,
+ int *status,
+ int options);
+
+int xc_waitdomain_core(int domain,
+ int *status,
+ int options);
+
/*
* DOMAIN MANAGEMENT FUNCTIONS
*/
float cpu_weight,
u32 *pdomid);
+
+int xc_domain_dumpcore(int xc_handle,
+ u32 domid,
+ const char *corename);
+
+
/**
* This function pauses a domain. A paused domain still exists in memory
* however it does not receive any timeslices from the hypervisor.
--- /dev/null
+#include "xc_private.h"
+#define ELFSIZE 32
+#include "xc_elf.h"
+#include <stdlib.h>
+#include <zlib.h>
+
+/* number of pages to write at a time */
+#define DUMP_INCREMENT 4 * 1024
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+static int
+copy_from_domain_page(int xc_handle,
+ u32 domid,
+ unsigned long *page_array,
+ unsigned long src_pfn,
+ void *dst_page)
+{
+ void *vaddr = xc_map_foreign_range(
+ xc_handle, domid, PAGE_SIZE, PROT_READ, page_array[src_pfn]);
+ if ( vaddr == NULL )
+ return -1;
+ memcpy(dst_page, vaddr, PAGE_SIZE);
+ munmap(vaddr, PAGE_SIZE);
+ return 0;
+}
+
+int
+xc_domain_dumpcore(int xc_handle,
+ u32 domid,
+ const char *corename)
+{
+ vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt;
+ unsigned long nr_pages;
+ unsigned long *page_array;
+ xc_domaininfo_t st_info, *info = &st_info;
+ int i, dump_fd;
+ char *dump_mem, *dump_mem_start = NULL;
+ struct xc_core_header header;
+
+ if ((dump_fd = open(corename, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)) < 0) {
+ PERROR("Could not open corefile %s: %s", corename, strerror(errno));
+ goto error_out;
+ }
+
+ if ((dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == 0) {
+ PERROR("Could not allocate dump_mem");
+ goto error_out;
+ }
+
+ if (xc_domain_getfullinfo(xc_handle, domid, 0/* XXX hardcode */, info, ctxt)) {
+ PERROR("Could not get full info for domain");
+ goto error_out;
+ }
+
+ nr_pages = info->tot_pages;
+ header.xch_magic = 0xF00FEBED;
+ header.xch_nr_vcpus = 1; /* no interface to query at the moment */
+ header.xch_nr_pages = nr_pages;
+ header.xch_ctxt_offset = sizeof(struct xc_core_header);
+ header.xch_index_offset = sizeof(struct xc_core_header) +
+ sizeof(vcpu_guest_context_t);
+ header.xch_pages_offset = round_pgup(sizeof(struct xc_core_header) +
+ sizeof(vcpu_guest_context_t) + nr_pages * sizeof(unsigned long));
+
+ write(dump_fd, &header, sizeof(struct xc_core_header));
+ write(dump_fd, ctxt, sizeof(st_ctxt));
+
+ if ((page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL) {
+ printf("Could not allocate memory\n");
+ goto error_out;
+ }
+ if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) {
+ printf("Could not get the page frame list\n");
+ goto error_out;
+ }
+ write(dump_fd, page_array, nr_pages * sizeof(unsigned long));
+ lseek(dump_fd, header.xch_pages_offset, SEEK_SET);
+ for (dump_mem = dump_mem_start, i = 0; i < nr_pages; i++) {
+ copy_from_domain_page(xc_handle, domid, page_array, i, dump_mem);
+ dump_mem += PAGE_SIZE;
+ if (((i + 1) % DUMP_INCREMENT == 0) || (i + 1) == nr_pages) {
+ if (write(dump_fd, dump_mem_start, dump_mem - dump_mem_start) <
+ dump_mem - dump_mem_start) {
+ PERROR("Partial write, file system full?");
+ goto error_out;
+ }
+ dump_mem = dump_mem_start;
+ }
+ }
+
+ close(dump_fd);
+ free(dump_mem_start);
+ return 0;
+ error_out:
+ if (dump_fd)
+ close(dump_fd);
+ if (dump_mem_start)
+ free(dump_mem_start);
+ return -1;
+}
* ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
*/
-long xc_ptrace(enum __ptrace_request request,
- pid_t pid, void *addr, void *data);
+
int waitdomain(int domain, int *status, int options);
char * ptrace_names[] = {
}
int
-waitdomain(int domain, int *status, int options)
+xc_waitdomain(int domain, int *status, int options)
{
dom0_op_t op;
int retval;
}
long
-xc_ptrace(enum __ptrace_request request, pid_t domid, void *addr, void *data)
+xc_ptrace(enum __ptrace_request request, pid_t domid, long eaddr, long edata)
{
dom0_op_t op;
int status = 0;
long retval = 0;
unsigned long *guest_va;
int cpu = VCPU;
+ void *addr = (char *)eaddr;
+ void *data = (char *)edata;
op.interface_version = DOM0_INTERFACE_VERSION;
--- /dev/null
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include "xc_private.h"
+#include <asm/elf.h>
+#include <time.h>
+
+
+#define BSD_PAGE_MASK (PAGE_SIZE-1)
+#define PG_FRAME (~((unsigned long)BSD_PAGE_MASK)
+#define PDRSHIFT 22
+#define PSL_T 0x00000100 /* trace enable bit */
+
+#define VCPU 0 /* XXX */
+
+/*
+ * long
+ * ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
+ */
+
+
+struct gdb_regs {
+ long ebx; /* 0 */
+ long ecx; /* 4 */
+ long edx; /* 8 */
+ long esi; /* 12 */
+ long edi; /* 16 */
+ long ebp; /* 20 */
+ long eax; /* 24 */
+ int xds; /* 28 */
+ int xes; /* 32 */
+ int xfs; /* 36 */
+ int xgs; /* 40 */
+ long orig_eax; /* 44 */
+ long eip; /* 48 */
+ int xcs; /* 52 */
+ long eflags; /* 56 */
+ long esp; /* 60 */
+ int xss; /* 64 */
+};
+
+#define printval(x) printf("%s = %lx\n", #x, (long)x);
+#define SET_PT_REGS(pt, xc) \
+{ \
+ pt.ebx = xc.ebx; \
+ pt.ecx = xc.ecx; \
+ pt.edx = xc.edx; \
+ pt.esi = xc.esi; \
+ pt.edi = xc.edi; \
+ pt.ebp = xc.ebp; \
+ pt.eax = xc.eax; \
+ pt.eip = xc.eip; \
+ pt.xcs = xc.cs; \
+ pt.eflags = xc.eflags; \
+ pt.esp = xc.esp; \
+ pt.xss = xc.ss; \
+ pt.xes = xc.es; \
+ pt.xds = xc.ds; \
+ pt.xfs = xc.fs; \
+ pt.xgs = xc.gs; \
+}
+
+#define SET_XC_REGS(pt, xc) \
+{ \
+ xc.ebx = pt->ebx; \
+ xc.ecx = pt->ecx; \
+ xc.edx = pt->edx; \
+ xc.esi = pt->esi; \
+ xc.edi = pt->edi; \
+ xc.ebp = pt->ebp; \
+ xc.eax = pt->eax; \
+ xc.eip = pt->eip; \
+ xc.cs = pt->xcs; \
+ xc.eflags = pt->eflags; \
+ xc.esp = pt->esp; \
+ xc.ss = pt->xss; \
+ xc.es = pt->xes; \
+ xc.ds = pt->xds; \
+ xc.fs = pt->xfs; \
+ xc.gs = pt->xgs; \
+}
+
+
+#define vtopdi(va) ((va) >> PDRSHIFT)
+#define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff)
+
+/* XXX application state */
+
+
+static long nr_pages = 0;
+static unsigned long *p2m_array = NULL;
+static unsigned long *m2p_array = NULL;
+static unsigned long pages_offset;
+static unsigned long cr3[MAX_VIRT_CPUS];
+static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS];
+
+/* --------------------- */
+
+static unsigned long
+map_mtop_offset(unsigned long ma)
+{
+ return pages_offset + (m2p_array[ma >> PAGE_SHIFT] << PAGE_SHIFT);
+}
+
+
+static void *
+map_domain_va(unsigned long domfd, int cpu, void * guest_va)
+{
+ unsigned long pde, page;
+ unsigned long va = (unsigned long)guest_va;
+
+ static unsigned long cr3_phys[MAX_VIRT_CPUS];
+ static unsigned long *cr3_virt[MAX_VIRT_CPUS];
+ static unsigned long pde_phys[MAX_VIRT_CPUS];
+ static unsigned long *pde_virt[MAX_VIRT_CPUS];
+ static unsigned long page_phys[MAX_VIRT_CPUS];
+ static unsigned long *page_virt[MAX_VIRT_CPUS];
+
+ if (cr3[cpu] != cr3_phys[cpu])
+ {
+ cr3_phys[cpu] = cr3[cpu];
+ if (cr3_virt[cpu])
+ munmap(cr3_virt[cpu], PAGE_SIZE);
+ if ((cr3_virt[cpu] = mmap(NULL, PAGE_SIZE, PROT_READ,
+ MAP_PRIVATE, domfd, map_mtop_offset(cr3_phys[cpu]))) ==
+ (unsigned long*)0xffffffff)
+ {
+ perror("mmap failed");
+ goto error_out;
+ }
+ }
+ if ((pde = cr3_virt[cpu][vtopdi(va)]) == 0) /* logical address */
+ goto error_out;
+ if (ctxt[cpu].flags & VGCF_VMX_GUEST)
+ pde = p2m_array[pde >> PAGE_SHIFT] << PAGE_SHIFT;
+ if (pde != pde_phys[cpu])
+ {
+ pde_phys[cpu] = pde;
+ if (pde_virt[cpu])
+ munmap(pde_virt[cpu], PAGE_SIZE);
+ if ((pde_virt[cpu] = mmap(NULL, PAGE_SIZE, PROT_READ,
+ MAP_PRIVATE, domfd, map_mtop_offset(pde_phys[cpu]))) == NULL)
+ goto error_out;
+ }
+ if ((page = pde_virt[cpu][vtopti(va)]) == 0) /* logical address */
+ goto error_out;
+ if (ctxt[cpu].flags & VGCF_VMX_GUEST)
+ page = p2m_array[page >> PAGE_SHIFT] << PAGE_SHIFT;
+ if (page != page_phys[cpu])
+ {
+ page_phys[cpu] = page;
+ if (page_virt[cpu])
+ munmap(page_virt[cpu], PAGE_SIZE);
+ if ((page_virt[cpu] = mmap(NULL, PAGE_SIZE, PROT_READ,
+ MAP_PRIVATE, domfd, map_mtop_offset(page_phys[cpu]))) == NULL) {
+ printf("cr3 %lx pde %lx page %lx pti %lx\n", cr3[cpu], pde, page, vtopti(va));
+ page_phys[cpu] = 0;
+ goto error_out;
+ }
+ }
+ return (void *)(((unsigned long)page_virt[cpu]) | (va & BSD_PAGE_MASK));
+
+ error_out:
+ return 0;
+}
+
+int
+xc_waitdomain_core(int domfd, int *status, int options)
+{
+ int retval = -1;
+ int nr_vcpus;
+ int i;
+ xc_core_header_t header;
+
+ if (nr_pages == 0) {
+
+ if (read(domfd, &header, sizeof(header)) != sizeof(header))
+ return -1;
+
+ nr_pages = header.xch_nr_pages;
+ nr_vcpus = header.xch_nr_vcpus;
+ pages_offset = header.xch_pages_offset;
+
+ if (read(domfd, ctxt, sizeof(vcpu_guest_context_t)*nr_vcpus) !=
+ sizeof(vcpu_guest_context_t)*nr_vcpus)
+ return -1;
+
+ for (i = 0; i < nr_vcpus; i++) {
+ cr3[i] = ctxt[i].pt_base;
+ }
+ if ((p2m_array = malloc(nr_pages * sizeof(unsigned long))) == NULL) {
+ printf("Could not allocate p2m_array\n");
+ goto error_out;
+ }
+ if (read(domfd, p2m_array, sizeof(unsigned long)*nr_pages) !=
+ sizeof(unsigned long)*nr_pages)
+ return -1;
+
+ if ((m2p_array = malloc((1<<20) * sizeof(unsigned long))) == NULL) {
+ printf("Could not allocate m2p array\n");
+ goto error_out;
+ }
+ bzero(m2p_array, sizeof(unsigned long)* 1 << 20);
+
+ for (i = 0; i < nr_pages; i++) {
+ m2p_array[p2m_array[i]] = i;
+ }
+
+ }
+ retval = 0;
+ error_out:
+ return retval;
+
+}
+
+long
+xc_ptrace_core(enum __ptrace_request request, int domfd, long eaddr, long edata)
+{
+ int status = 0;
+ struct gdb_regs pt;
+ long retval = 0;
+ unsigned long *guest_va;
+ int cpu = VCPU;
+ void *addr = (char *)eaddr;
+ void *data = (char *)edata;
+
+#if 0
+ printf("%20s %d, %p, %p \n", ptrace_names[request], domid, addr, data);
+#endif
+ switch (request) {
+ case PTRACE_PEEKTEXT:
+ case PTRACE_PEEKDATA:
+ if ((guest_va = (unsigned long *)map_domain_va(domfd, cpu, addr)) == NULL) {
+ status = EFAULT;
+ goto error_out;
+ }
+
+ retval = *guest_va;
+ break;
+ case PTRACE_POKETEXT:
+ case PTRACE_POKEDATA:
+ if ((guest_va = (unsigned long *)map_domain_va(domfd, cpu, addr)) == NULL) {
+ status = EFAULT;
+ goto error_out;
+ }
+ *guest_va = (unsigned long)data;
+ break;
+ case PTRACE_GETREGS:
+ case PTRACE_GETFPREGS:
+ case PTRACE_GETFPXREGS:
+ if (request == PTRACE_GETREGS) {
+ SET_PT_REGS(pt, ctxt[cpu].user_regs);
+ memcpy(data, &pt, sizeof(elf_gregset_t));
+ } else if (request == PTRACE_GETFPREGS)
+ memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
+ else /*if (request == PTRACE_GETFPXREGS)*/
+ memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
+ break;
+ case PTRACE_ATTACH:
+ retval = 0;
+ break;
+ case PTRACE_SETREGS:
+ case PTRACE_SINGLESTEP:
+ case PTRACE_CONT:
+ case PTRACE_DETACH:
+ case PTRACE_SETFPREGS:
+ case PTRACE_SETFPXREGS:
+ case PTRACE_PEEKUSER:
+ case PTRACE_POKEUSER:
+ case PTRACE_SYSCALL:
+ case PTRACE_KILL:
+#ifdef DEBUG
+ printf("unsupported xc_ptrace request %s\n", ptrace_names[request]);
+#endif
+ status = ENOSYS;
+ break;
+ case PTRACE_TRACEME:
+ printf("PTRACE_TRACEME is an invalid request under Xen\n");
+ status = EINVAL;
+ }
+
+ if (status) {
+ errno = status;
+ retval = -1;
+ }
+ error_out:
+ return retval;
+}
* Definitions for the 'xc' object type.
*/
+static PyObject *pyxc_domain_dumpcore(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ char *corefile;
+
+ static char *kwd_list[] = { "dom", "corefile", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list, &dom, &corefile) )
+ goto exit;
+
+ if ( (corefile == NULL) || (corefile[0] == '\0') )
+ goto exit;
+
+ if ( xc_domain_dumpcore(xc->xc_handle, dom, corefile) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+
+ exit:
+ return NULL;
+}
+
static PyObject *pyxc_domain_create(PyObject *self,
PyObject *args,
PyObject *kwds)
" mem_kb [int, 0]: Memory allocation, in kilobytes.\n"
"Returns: [int] new domain identifier; -1 on error.\n" },
+ { "domain_dumpcore",
+ (PyCFunction)pyxc_domain_dumpcore,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "dump core of a domain.\n"
+ " dom [int]: Identifier of domain to be paused.\n\n"
+ " corefile [string]: Name of corefile to be created.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
{ "domain_pause",
(PyCFunction)pyxc_domain_pause,
METH_VARARGS | METH_KEYWORDS, "\n"